#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <queue>

/*
这种方法的一个问题是每次我们想要添加一条新消息时，我们都必须执行以下操作： 
添加处理函数 
修改 Message 类以添加新的 id 和新的 param 
修改 handler 线程以将 case 添加到 switch 语句
*/
struct Color {
    int r;
    int g;
    int b;
};

struct Message {
    enum class Id {
        SET_STATE = 0,
        SET_INTENSITY,
        SET_COLOR,
        TERMINATE
    };
    union Params {
        Color rgb;
        uint8_t intensity;
        bool state;
    };

    Id id;
    Params params;
};

void PrintState(const bool state) {
    std::cout << "SetState " << state << "\n";
}

void PrintIntensity(const uint8_t intensity) {
    std::cout << "SetIntensity " << (unsigned int) intensity << "\n";
}

void PrintColor(const Color color) {
    std::cout << "SetColor " << color.r << ", " << color.g << ", " << color.b << "\n";
}


std::condition_variable cv;
std::mutex m;
std::queue<Message> msg_queue;

Message GetMessage() {
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, [](){ return !msg_queue.empty(); } ); //消息队列不为空 
    
    Message message;
    message = msg_queue.front();
    msg_queue.pop();
    return message;      
}

void PutMessage(const Message& message) {
    std::lock_guard<std::mutex> lk(m);
    msg_queue.push(message);
    cv.notify_one(); 

}

void controller()
{
    Color white = {255, 255, 255};
    uint8_t intensity = 255;

    PutMessage(Message{Message::Id::SET_STATE, true});      // switch on
    PutMessage(Message{Message::Id::SET_INTENSITY, intensity});   // set the highest intensity
    PutMessage(Message{Message::Id::SET_COLOR, white});     // set color to white
    PutMessage(Message{Message::Id::SET_STATE, false});     // switch off
    PutMessage(Message{Message::Id::TERMINATE});
}

void handler()
{
    while (true) {
        const Message msg = GetMessage();
        switch (msg.id) {
            case Message::Id::SET_STATE:
                PrintState(msg.params.state);
                break;
            case Message::Id::SET_INTENSITY:
                PrintIntensity(msg.params.intensity);
                break;
            case Message::Id::SET_COLOR:
                PrintColor(msg.params.rgb);
                break;
            case Message::Id::TERMINATE:
                return;  
            default:
                break;
        }
    }
}


int main() {
    std::thread c(handler);
    std::thread p(controller);
    
    c.join();
    p.join();

    return 0;
}
